function models_struct =cross_validation (input,list_of_regions,minor_size_list)

% This function  calculate more accurate FLD classifier model' struct - it's running 
% a cross validation algorithm - we take some points from the data, and use them as a test data.
% the rest of the points are used as the model's data. then, we are classifying the test data using
% the model based on the rest of the data, and check our error. at last, we return the best result's model.

% Function Inputs:
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
% input - mat of num_featuresXnum_regions.
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
% list_of_regions - suggested label for each region, by the ground truth.
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
% minor_size_list - array of amount of points to take from the trained model and to classify them.
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

% Function Outputs:
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
%  models_struct - struct of models that are the output of FLD classifier, after the cross validation.
%-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

% Global Inputs:
% model_p.cross_validation_NIT
% model_p.cross_validation_display

global model_p
NIT=model_p.cross_validation_NIT;
display=model_p.cross_validation_display;

size_minor=length(minor_size_list);
errors=zeros(NIT,size_minor);
lists=cell(NIT,size_minor);

for k=1:size_minor
    minor_size=minor_size_list(k);
    str=sprintf('Calculating Cross Validation, minor size - %d',minor_size);
    h = waitbar(0,str);
    for i=1:NIT
        waitbar(i/NIT);

        % setting the data to be tested (minor_input), and the trained data to be set as the model (major_input)
        rp=randperm(length(list_of_regions));
        minor_input=input(:,rp(1:minor_size));
        minor_list=list_of_regions(rp(:,1:minor_size));
        major_input=input(:,rp(minor_size+1:end));
        major_list=list_of_regions(rp(:,minor_size+1:end));
        
        % building the model
        [models_struct, is_nan] = create_models_struct( major_input, major_list);

        % classifying the minor_input using the model that is based on the major_input
        [ypred_1,conf_1] = fld_classify(minor_input,models_struct.model_1); 
        [ypred_2,conf_2] = fld_classify(minor_input,models_struct.model_2); 
        [ypred_3,conf_3] = fld_classify(minor_input,models_struct.model_3); 
        [ypred_4,conf_4] = fld_classify(minor_input,models_struct.model_4); 
        ypred_mat=[ypred_1;ypred_2;ypred_3;ypred_4];
        prob=[fld2prob(conf_1);fld2prob(conf_2);fld2prob(conf_3);fld2prob(conf_4)];
        [max_value,label_indices]=max(prob.*(ypred_mat==1),[],1); % getting best score only from labels 'one'
        ypred=label_indices;
        ypred(max_value==0)=0; % maybe all labels are 'all'
        
        % setting the error output
        errors(i,k)=sum(ypred~=minor_list)/minor_size;
        lists{i,k}=rp;
    end
    close (h);
end

% displaying the statistic results
if (display)
    disp('min of all errors');
    min_place_list=min(errors)
    disp('mean of all errors');
    mean(errors)
    disp('var of all errors');
    var(errors)
    disp('std of all errors');
    std(errors)
end

clear models_struct;

% now setting the winning minor_input that gave the best results
[min_value,min_place]=min(min_place_list);
minor_size=minor_size_list(min_place);
[min_value,min_index]=min(errors(:,min_place));
sprintf('error is %1.4f',min_value)
rp=lists{min_index,min_place};
minor_input=input(:,rp(1:minor_size));
minor_list=list_of_regions(rp(:,1:minor_size));
major_input=input(:,rp(minor_size+1:end));
major_list=list_of_regions(rp(:,minor_size+1:end));

% building the winning model
[models_struct, is_nan] = create_models_struct( major_input, major_list);
